﻿using System;
using System.Collections.Generic;
using System.Threading;

namespace DesignPatterns
{
    class Program
    {
        static void Main(string[] args)
        {
            #region 设计模式六大原则
            /*
              https://www.cnblogs.com/netxiaohui/category/1983228.html
              1.单一职责
              2.里氏替换
                  子类可以替换父类
              3.依赖倒转
                  要依赖接口
              4.接口隔离
                  一个类对另外一个类的依赖应该建立在最小接口上
              5.迪米特法则(又叫最少知道原则)
                  一个对象对其他对象保持最少的了解
              6.开闭原则
                  对扩展开放,对修改关闭
               */
            #endregion

            //创建型
            //单抽元(原)件(建)厂(简单工厂)

            #region 简单工厂模式
            //一个工厂可以创建多个对象
            //EasyFactory.GetSendInterface(1).SendLandGoods("tel");
            //EasyFactory.GetSendInterface(2).SendLandGoods("tel");
            #endregion

            #region 抽象工厂模式
            //定义了工厂标准,
            //每个类由单独的工厂来创建,不再由一个工厂类包办
            //降低了耦合

            ////公司A
            //AbstractFactory aCompanyFactory = new CompanyAAbstractFactory();
            //aCompanyFactory.SendGood().GetGood();

            ////公司B
            //var bCompanyFactory = new CompanyBAbstractFactory();
            //bCompanyFactory.SendGood().GetGood();
            #endregion

            #region 单例模式
            ////类就只有一个实例
            ////懒汉模式就是懒加载,要注意线程安全
            ////饿汗模式就程序一启动就加载,不管你是否用懂啊
            //Console.WriteLine("多线程进行访问");
            //Thread processOne = new Thread(() => {
            //    TestSingleton("阿辉");
            //});

            //Thread processTwo = new Thread(() => {
            //    TestSingleton("阿七");
            //});

            //processOne.Start();
            //processTwo.Start();

            //processOne.Join();
            //processTwo.Join();

            //Console.ReadKey();

            ////饿汗模式
            //Singleton2.GetInstance();
            #endregion

            #region 建造者模式
            // 不同的类构造对象的不同部位,最后构造一个复杂的对象            

            //SendModelBuilder smb = new BeiJingBuilder();

            //var director = new BuilderPattern();
            //Matter matter = director.SendModel(smb);

            //Console.WriteLine("包装类型：" + matter.PackStyle);
            //Console.WriteLine("运输方式：" + matter.TransportWay);
            //Console.WriteLine("是否有税费：" + matter.IsHaveTax);
            //Console.WriteLine("运费：" + matter.Money);
            //Console.WriteLine("信息：" + matter.DescriptionInfo);

            #endregion

            #region 原型模式
            ////原型实例指定创建对象的种类，并且通过拷贝这些原型创建新的对象
            //ConcretePrototype1 p1 = new ConcretePrototype1("I");
            //ConcretePrototype1 c1 = (ConcretePrototype1)p1.Clone();
            //Console.WriteLine("Cloned: {0}", c1.Id);

            //ConcretePrototype2 p2 = new ConcretePrototype2("II");
            //ConcretePrototype2 c2 = (ConcretePrototype2)p2.Clone();
            //Console.WriteLine("Cloned: {0}", c2.Id);
            //Console.Read();

            #endregion

            //行为模式
            /*
                观摩对策,责令解放,戒(中)忘台(态)
             */

            #region 观察者
            ////定义一种订阅机制，可在对象事件发生时通知多个“观察者”该对象的其他对象。
            //IObSubject subject = new ObSubject() {  Name="test111" };
            //subject.Attach(new ObserverA());
            //subject.Attach(new ObserverB());
            //subject.Notify();

            #endregion

            #region 策略
            //策略模式是一种行为设计模式，它能让你定义一系列算法，并将每种算法分别放入独立的类中，以使算法的对象能够相互替换。
            //可以达到将算法和实际业务剥离的效果，减少彼此之间的耦合。而且也满足开闭原则，我们在后期添加新算法时，可以不用修改旧算法，就可以实现功能。
            //StragePatternContext context = new StragePatternContext(new SortAsc());
            //context.DoSometing();

            //context = new StragePatternContext(new SortDesc());
            //context.DoSometing();
            #endregion

            #region 备忘录
            //备忘录的设计实现方式，重点在于不更改原有类的基础上，增加备忘录存放记录。
            //就是把类的关键数据存到一个list中,要的时候一点点撤销恢复就行了

            //Founder founder = new Founder();
            //founder.DoSomething();

            //Manager manager = new Manager(founder);
            //manager.Backup();

            //founder.DoSomething();
            //manager.Backup();

            //founder.DoSomething();

            //manager.Undo();
            //manager.Undo();
            //manager.Undo();
            //manager.Undo();

            #endregion

            #region 中介者
            ////中介者模式顾名思义，可以用我们平时生活中的房产中介去理解。房产中介就是房子拥有者和想买房子人直接的桥梁，
            ////不让二者直接交易，通过中介去做桥梁，进行沟通和交易。
            ////将多对多简化成了一对多的关系

            //Console.WriteLine("一个租客看房：");
            /////初始化中介
            //HouseMediator mediator = new HouseMediator();

            /////初始化房屋信息
            //SmallHouseColleague smallHouseColleague = new SmallHouseColleague();
            //TwoHouseColleague twoHouseColleague = new TwoHouseColleague();
            //ThreeHouseColleague threeHouseColleague = new ThreeHouseColleague();

            /////中介获取房屋信息
            //mediator.SetSmallHouse(smallHouseColleague);
            //mediator.SetTwoHouse(twoHouseColleague);
            //mediator.SetThreeHouse(threeHouseColleague);

            /////租户A需要两居室、提供看房
            //mediator.Common("两居室");

            ////租户B需要四居室、暂无房源
            //mediator.Common("四居室");

            //Console.ReadKey();

            #endregion

            #region 迭代器
            //不用暴露底层集合的表现形式,允许外界遍历所有元素
            //实现IEnumerator IEnumerable
            //var collection = new PeopleCollection();
            //collection.AddItem("阿五");
            //collection.AddItem("阿六");
            //collection.AddItem("阿七");
            //Console.WriteLine("遍历下");
            //foreach (var item in collection)
            //{
            //    Console.WriteLine(item);
            //}
            //Console.WriteLine("倒序");
            //collection.ReverseDirection();
            //foreach (var item in collection)
            //{
            //    Console.WriteLine(item);
            //}
            //Console.ReadKey();
            #endregion

            #region 命令
            //此模式在执行一些业务逻辑比较条理化的需求时，可以被使用。
            //通过将业务中的链条关系，整合成一个个命令，调用者直接调用对应的命令接口就行，根本不需要知道是谁，如何提供的方法。
            //而且实现方法的人也不知道谁调用的，如何调用的，这些对于它们来说都是不相关的，也满足单一职责和开闭原则。

            //实现一个任务链条,挨个调用

            //InvokerClient invokerClient = new InvokerClient();
            //invokerClient.SetOnOne(new SimpleCommand("simple"));
            //invokerClient.SetOnTwo(new ComplexCommand(new Receiver(), "do111", "do222"));
            //invokerClient.DoExecute();

            #endregion


            #region 模板
            //模板方法模式是一种行为设计模式，它在超类中定义一个算法的框架，允许子类在不修改结构的情况下重写算法的特定步骤。
            //模板方法模式建议将算法分解为一系列步骤，然后将这些步骤改为方法，最后在“模板方法”中依次调用这些方法。

            //AbstractMethod abstractMethod = new Class1();
            //abstractMethod.TestMethod();


            //abstractMethod = new Class2();
            //abstractMethod.TestMethod();

            #endregion

            #region 状态模式
            //状态模式是一种行为设计模式，让你能在一个对象的内部状态变化时改变其行为，使其看上去就像改变了自身所属的类一样。
            //状态模式建议为对象的所有可能状态新建一个类，然后将所有状态的对应行为抽取到这些类中。

            //状态模式的的思想是，状态之间的切换，在状态A执行完毕后自己控制状态指向状态B。状态模式是不停的切换状态执行。

            //与策略模式很类似,只是这里的状态之间可以互相调用,一个状态可以变成另外一个状态

            //StateContext stateContext = new StateContext();
            //stateContext.SetStateContext(new OneState());
            //stateContext.RequestOne();


            #endregion


            #region 责任链
            //责任链模式是一种行为设计模式，允许你将请求沿着处理者链进行发送。收到请求后，每个处理者均可对请求进行处理，或将其传递给链上的下个处理者。

            var monkey = new MonkeyHandler();
            var squirrel = new SquirreHandler();
            var dog = new DogHandler();

            monkey.SetNext(squirrel).SetNext(dog);      //构建链条

            Console.WriteLine("----------第一次");
            ClientHandel.ClientCode(monkey);
            Console.WriteLine();

            //Console.WriteLine("第二次");
            //ClientHandel.ClientCode(squirrel);

            //Console.WriteLine("第三次");
            //ClientHandel.ClientCode(dog);
            //Console.ReadKey();

            #endregion

            #region  访问者
            ////元素挨个被外部类处理
            //ObjectStructure objectStructure = new ObjectStructure();

            //objectStructure.attach(new ConcreteElementA());
            //objectStructure.attach(new ConcreteElementB());

            //ConcreteVisitor1 visitor1 = new ConcreteVisitor1();
            //ConcreteVisitor2 visitor2 = new ConcreteVisitor2();

            //objectStructure.accept(visitor1);
            //objectStructure.accept(visitor2);

            #endregion


            #region 解释器模式
            //把类挨个给外部的类访问

            Context context = new Context();
            List<AbstractExpression> list = new List<AbstractExpression>();

            list.Add(new TerminalExpression());
            list.Add(new NonterminalExpression());
            list.Add(new TerminalExpression());
            list.Add(new TerminalExpression());

            foreach (AbstractExpression abstractExpression in list)
            {
                abstractExpression.Interpret(context);
            }

            #endregion

            //结构型

            //外侨组员戴配饰
            /*
                        
             */
            #region 外观模式
            FacadePattern facadePattern = new FacadePattern();
            Console.WriteLine(facadePattern.Operation());
            #endregion

            #region 桥接模式
            //将类中复杂多变的部分拆分成接口,其他稳定的部分为实现
            //接口部分通过变量传入

            //桥接模式就是通过将抽象部分与实现部分分离，把多种可匹配的使用进行组合。其实就是在A类中含有B类接口，通过构造函数传递B类的实现，这个B类就是设计的桥。
            //它是一种结构型设计模式，可将一个大类或一系列紧密相关的类拆分为抽象和实现两个独立的层次结构，从而能在开发时分别使用。

            Pay wxPay = new wxPay(new FaceRecognition());
            var result = wxPay.Validation(001, "阿辉");
            Console.WriteLine(result);

            Pay zfbPay = new zfbPay(new PasswardInput());
            result = zfbPay.Validation(002, "阿七");
            Console.WriteLine(result);
            Console.ReadKey();

            #endregion

            #region 组合模式
            //将一组类似的类添加到一起挨个调用

            Client client = new Client();

            Leaf leaf = new Leaf();
            Console.WriteLine("调用叶子......");

            client.ClientCode(leaf);

            Console.WriteLine("---------------");



            Composite tree = new Composite();

            Composite branch1 = new Composite();
            branch1.Add(new Leaf());
            branch1.Add(new Leaf());

            Composite branch2 = new Composite();
            branch2.Add(new Leaf());

            tree.Add(branch1);
            tree.Add(branch2);
            Console.WriteLine("调用复杂对象......");
            client.ClientCode(tree);

            Console.WriteLine("---");
            client.ClientCode2(tree, leaf);
            Console.ReadKey();

            #endregion

            #region 享元模式
            //共享通用对象，减少内存的使用
            //将一些对象提前添加到list中缓存起来
            var factory = new FlyweightFactory(
                    new Car { Company = "Chevrolet", Model = "Camaro2018", Color = "pink" },
              new Car { Company = "Mercedes Benz", Model = "C300", Color = "black" },
              new Car { Company = "Mercedes Benz", Model = "C500", Color = "red" },
              new Car { Company = "BMW", Model = "M5", Color = "red" },
              new Car { Company = "BMW", Model = "X6", Color = "white" }
              );

            factory.listFlyweights();

            addCarToPoliceDatabase(factory, new Car
            {
                Number = "CL234IR",
                Owner = "James Doe",
                Company = "BMW",
                Model = "M5",
                Color = "red"
            });

            addCarToPoliceDatabase(factory, new Car
            {
                Number = "CL234IR",
                Owner = "James Doe",
                Company = "BMW",
                Model = "X1",
                Color = "red"
            });

            factory.listFlyweights();

            Console.ReadKey();
            #endregion

            #region 代理模式
            //对另外一个类进行了包装,屏蔽了一些细节,提供对外访问

            //服务接口 声明服务接口，代理必须遵循该接口才能伪装成服务对象。
            //访问代理就等于在访问对象本身,代理与对象要实现同一个接口

            //var client = new ProxPatternClient();

            //Proxy proxy = new Proxy();
            //client.ClientCode(proxy);
            //Console.ReadKey();

            #endregion

            #region 适配器
            ////通过封装 将复杂的转换过程 隐藏于幕后。
            /////被封装的对象甚至察觉不到适配器的存在。

            ////与代理模式,外观模式都很类型
            ////代理模式要求代理类与被代理类实现同样的接口
            ////外观模式,是外观类包装了多个内部方法
            ////适配器更像简易版的代理模式

            //Console.WriteLine("Start Test Adapter Mode");

            ////实例化老代码模块
            //Adaptee tempAdaptee = new Adaptee();

            //ITarget adapter = new Adapter(tempAdaptee);

            ////通过实现的接口去调用老代码模块中的方法。
            //var showResult = adapter.GetRequest();

            //Console.WriteLine(showResult);

            //Console.ReadKey();


            #endregion

            #region 装饰
            //在原始类包装一下,与原始类继承同一的接口
            DComponent component = new ConcreteComponent();
            //第一次修饰
            component = new ConcreteDecoratorA(component);
            //第二次修饰
            component = new ConcreteDecoratorB(component);
            //修饰后运行
            component.operation();
            #endregion

            Console.WriteLine("Hello World!");
        }

        #region 
        static void TestSingleton(string value)
        {
            SinglePattern s = SinglePattern.GetInstance(value);
            Console.WriteLine(s.Value);
        }

        static void addCarToPoliceDatabase(FlyweightFactory factory, Car car)
        {
            Console.WriteLine("添加一个新Car");
            var flyweight = factory.GetFlyweight(new Car
            {
                Color = car.Color,
                Model = car.Model,
                Company = car.Company
            });

            flyweight.Operation(car);
        }
        #endregion

    }
}
